/*
 * Author: nicolas.bredeche(@)lri.fr
 * Created on 7 janv. 2006
 * 
 */

package picoevo.tutorials.gp.symbolicregression;

import picoevo.core.evolution.ParameterSet;
import picoevo.core.evolution.SelectionOperator;
import picoevo.core.representation.World;
import picoevo.ext.evolution.SelectionOperator_MuLambda;
import picoevo.ext.representation.Population_SimplePopulation;
import picoevo.gp.evolution.InitialisationOperator_Element_Node_TreeGP;
import picoevo.gp.evolution.InitialisationOperator_Individual_SingleRegister_TreeGP;
import picoevo.gp.evolution.InitialisationOperator_Population_TreeGP;
import picoevo.gp.evolution.StatisticsOperator_Population_TreeGP;
import picoevo.toolbox.Dictionary;
import picoevo.toolbox.Display;
import picoevo.toolbox.Misc;
import picoevo.toolbox.Version;

public class Main_SymbolicRegression {
	public static void launchEvolution() {
		Display.info("#### Symbolic Regression ####"); // Tree GP ..

		// 1 - create an Evolution environment along with a single embedded
		// Population

		ParameterSet parameterSet = new ParameterSet();

		parameterSet.setProperty("Mu", 50);
		parameterSet.setProperty("Lambda", 450);
		parameterSet.setProperty("MuPlusLambda", true);
		parameterSet.setProperty("Generations", 51);
		parameterSet.setProperty("InitPopSize", 500);
		parameterSet.setProperty("OptimisationFlag", Boolean.toString(Dictionary.Minimisation));

		parameterSet.setProperty("MutationRate", 0.00);
		parameterSet.setProperty("CrossoverRate", 0.9);
		parameterSet.setProperty("EphemeralConstantMutationRate", 0.01);
		parameterSet.setProperty("crossover_nodeVsLeafProportion", 0.9);

		parameterSet.setProperty("MaxInitDepth", 6);
		parameterSet.setProperty("MaxRunningDepth", 17);

		// parameterSet.put("SelectionOperator",new
		// SelectionOperator_ClassicKozaGP("ClassicKozaGP"));
		// parameterSet.put("SelectionOperator",new
		// SelectionOperator_ProgressiveVariation("ProgressiveVariation")); //
		// testing...
		parameterSet.setProperty("SelectionOperator", new SelectionOperator_MuLambda("MULAMBDA"));
		parameterSet.setProperty("EvaluationOperator_Individual", new EvaluationOperator_Individual_SymReg_Polynomial("symreg"));
		// parameterSet.put("EvaluationOperator_Individual",new
		// EvaluationOperator_Individual_SymReg_Sinus("symregWithSinus"));
		parameterSet.setProperty("PopulationInitialisationOperator", new InitialisationOperator_Population_TreeGP("symreg"));
		parameterSet.setProperty("IndividualInitialisationOperator", new InitialisationOperator_Individual_SingleRegister_TreeGP("symreg"));
		parameterSet.setProperty("ElementInitialisationOperator", new InitialisationOperator_Element_Node_TreeGP("symreg"));
		parameterSet.setProperty("PopulationStatisticsOperator", new StatisticsOperator_Population_TreeGP());

		// max: somme[i=0->n](2^i), soit : 2^(n+1)-1, (pour n=11 : 4095) // test
		// (Xmxdefault, arbre max) : (1)pop=100;maxdepth=11
		// (2)pop=500;maxdepth=8 en "java -server" -- note : koza92book
		// p.104-105 : max permissible depth is 17 but usualy program do not
		// hold more than 500 nodes (note : maxinit is 6)
		// sur sim86: 100/14

		String timenow = Misc.getCurrentTimeAsCompactString();

		parameterSet.setProperty("LogFilename", "log/logfile_symreg_" + timenow + ".data");

		parameterSet.check();
		parameterSet.displayInformation();
		parameterSet.displayInformation("log/logfile_symreg_" + timenow + ".param");

		Display.info("\n\n## initialization ##");

		World myWorld = new World("myEvolution", parameterSet);
		Population_SimplePopulation population = new Population_SimplePopulation("my population", myWorld);
		myWorld.registerPopulation(population);

		population.performInitialisation();

		// population.displayInformation();

		Display.debug("-------------------------------------------------");

		// population.performEvaluation();
		// population.displayInformation();
		// Display.debug("STOP TEST");

		// System.exit(0); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

		// 2 - evolution

		Display.info("\n\n## evolving ##");

		boolean isDisplay = true;

		for (int i = 0; i != myWorld.getTemplate().getIntProperty("Generations"); i++) {
			population.performEvaluation();
			if (isDisplay == true)
				Display.info("\n# Generation no." + population.getGenerationNumber());
			((SelectionOperator) (population.getTemplate().getObjectProperty("SelectionOperator"))).performSelection(population);
			if (isDisplay == true)
				Display.memorycheck();
			population.displayStatistics();
			population.logStatistics();
		}

		// population.displayInformation();

		// --------------------------------------------------

		/*
		 * Display.info("\n\n## evolving ##");
		 * 
		 * int displayFreq = 10;
		 * 
		 * for ( int i = 0 ; i != myWorld.getTemplate().getGenerations() ; i++ ) {
		 * if (i % displayFreq == 0) myWorld.evolveOneStep(true); else
		 * myWorld.evolveOneStep(false); } // maxOnePop.displayInformation();
		 */

		Display.info("\n\n\n## terminating ##\n");
	}

	public static void main(String[] args) {
		double startTime = System.currentTimeMillis();

		Version.displayCurrentReleaseInformation();

		Display.info("Running...");
		launchEvolution();
		Display.info("\nTerminated (" + ((System.currentTimeMillis() - startTime) / 1000) + "s elapsed).");
	}

}
